/**************************************************************************** 
* 
* Copyright (c) 2023  C*Core -   All Rights Reserved  
* 
* THIS SOFTWARE IS DISTRIBUTED "AS IS," AND ALL WARRANTIES ARE DISCLAIMED, 
* INCLUDING MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* 
* PROJECT     : CCFC2011BC           
* DESCRIPTION : can demo code
* HISTORY     : Initial version.
* @file     canfd_demo.c
* @version  1.1
* @date     2023 - 02 - 20
* @brief    Initial version.
*
*****************************************************************************/

#include "canfd_demo.h"

static volatile uint8_t g_CANFD_Test_Case_4_1_rx_received = FALSE; /* PRQA S 1504 */
static volatile uint8_t g_CANFD_Test_Case_5_1_tx_transferred = FALSE; /* PRQA S 1504 */

/*******************************************************************************
 * @brief      CANFD_Test_Case_1_1
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static uint32_t CANFD_Test_Case_1_1(void)
{
    uint32_t ret;
    uint32_t msg_id;
    CANFDDriver *canfd;
    CANFDConfig config;
    CANFDTxMsg tx_msg;
    CANFDRxMsg rx_msg;

    cc_memset((uint8_t *)&config, 0, sizeof(config));
    cc_memset((uint8_t *)&tx_msg, 0, sizeof(tx_msg));
    cc_memset((uint8_t *)&rx_msg, 0, sizeof(rx_msg));
    /* STEP1 Set initialization parameters */
    config.phy_para.use_bus_clk_src = TRUE;
    config.phy_para.preamble_bit_rate = CANFD_KBPS_500;
    config.phy_para.data_bit_rate = CANFD_KBPS_200;
    config.func_switch.outer_loop_back_en = TRUE;
    config.canfd_id = CANFD_MOD_ID_0;

    /* STEP2 Initializes the CANFD module */
    ret = Canfd_LLD_Init(&canfd, &config);
    if (ret != CANFD_OK)
    {
        return ret;
    }
    /* STEP3 Send the CANFD message */
    tx_msg.data_len = 64;
    tx_msg.data.word[0] = 0x76543210;
    tx_msg.data.byte[4] = 0x44;
    tx_msg.data.byte[5] = 0x55;
    tx_msg.data.byte[6] = 0x66;
    tx_msg.data.byte[7] = 0x70;
    tx_msg.data.word[15] = 0x76543210;
    //
    tx_msg.id = 0x11;
    tx_msg.is_fd_format_flag = TRUE;
    tx_msg.is_bit_rate_switch = TRUE;
    tx_msg.is_extern = TRUE;
    tx_msg.trans_buf = CANFD_TRANS_BUF_TYPE_PRIMARY;
    ret = Canfd_LLD_Send_Msg(canfd, &tx_msg, &msg_id);
    if (ret != CANFD_OK)
    {
        return ret;
    }
    delayms(20);
    /* STEP4 Receive the CANFD message */
    ret = Canfd_LLD_Recv_Msg(canfd, &rx_msg);
    if (ret != CANFD_OK)
    {
        return ret;
    }
    if (tx_msg.id != rx_msg.id)
    {
        return ~CANFD_OK;
    }
    return CANFD_OK;
}

/*******************************************************************************
 * @brief      CANFD_Test_Case_2_1
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static uint32_t CANFD_Test_Case_2_1(void)
{
    uint32_t ret;
    CANFDDriver *canfd;
    CANFDConfig config;
    CANFDRxMsg rx_msg;
    int32_t count = 20;

    cc_memset((uint8_t *)&config, 0, sizeof(config));
    cc_memset((uint8_t *)&rx_msg, 0, sizeof(rx_msg));

    /* STEP1 Set initialization parameters */
    config.phy_para.use_bus_clk_src = TRUE;
    config.phy_para.preamble_bit_rate = CANFD_KBPS_500;
    config.func_switch.outer_loop_back_en = TRUE;
    config.canfd_id = CANFD_MOD_ID_0;
    config.filter[0].is_valid = TRUE;


    config.filter[0].id = 0x6c2;
    config.filter[0].mask = 0xfffffff0U;
    /* STEP2 Initializes the CANFD module */
    ret = Canfd_LLD_Init(&canfd, &config);
    if (ret != CANFD_OK)
    {
        return ret;
    }
    /* STEP3 Receive the CANFD message */
    while (count-- != 0) /* PRQA S 3440 */
    {
        ret = Canfd_LLD_Recv_Msg(canfd, &rx_msg);
        if (ret == CANFD_OK)
        {
            break;
        }
        delayms(2);
    }
    /* STEP4 Verify the CANFD message */
    return CANFD_OK;
}

/*******************************************************************************
 * @brief      CANFD_Test_Case_3_1
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static uint32_t CANFD_Test_Case_3_1(void)
{
    uint32_t ret;
    uint32_t canfd_id;
    uint32_t msg_id;
    CANFDDriver *canfd;
    CANFDConfig config;
    CANFDTxMsg tx_msg;
    CANFDRxMsg rx_msg;

    cc_memset((uint8_t *)&config, 0, sizeof(config));
    cc_memset((uint8_t *)&tx_msg, 0, sizeof(tx_msg));
    cc_memset((uint8_t *)&rx_msg, 0, sizeof(rx_msg));

    /* STEP1 Set initialization parameters */
    config.phy_para.use_bus_clk_src = TRUE;
    config.phy_para.preamble_bit_rate = CANFD_KBPS_500;
    config.func_switch.outer_loop_back_en = TRUE;

    /* STEP2 Initializes the CANFD module */
    for (canfd_id = 0; canfd_id < (uint32_t)CANFD_MOD_BUTT; canfd_id++)
    {
        config.canfd_id = (CANFDModId)canfd_id; /* PRQA S 4342 */
        ret = Canfd_LLD_Init(&canfd, &config);
        if (ret != CANFD_OK)
        {
            return ret;
        }
    }
    /* STEP3 Send the CANFD message */
    tx_msg.data_len = 32;
    tx_msg.data.word[0] = 0x5a5a5a5a;
    tx_msg.trans_buf = CANFD_TRANS_BUF_TYPE_SECONDARY;
    tx_msg.is_fd_format_flag = TRUE;
    for (canfd_id = 0; canfd_id < (uint32_t)CANFD_MOD_BUTT; canfd_id++)
    {
        tx_msg.id = 0x30U + canfd_id;
        tx_msg.data.byte[7] = (uint8_t)canfd_id;
        canfd = Canfd_LLD_Get_Driver((CANFDModId)canfd_id); /* PRQA S 4342 */
        ret = Canfd_LLD_Send_Msg(canfd, &tx_msg, &msg_id);
        if (ret != CANFD_OK)
        {
            return ret;
        }
        delayms(2); /* Multiplex CANFD multiplexing a transceiver scenario requires increased latency */
    }
    /* STEP4 Receive the CANFD message */
    return CANFD_OK;
}

/*******************************************************************************
 * @brief      CANFD_Test_Case_4_1_rx_received
 * @param[in]  CANFDDriver *drv, CANFDRxMsg * rx_msg
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void CANFD_Test_Case_4_1_rx_received(CANFDDriver *drv, CANFDRxMsg * rx_msg) /* PRQA S 3673 */
{
    if (drv->id != CANFD_MOD_ID_0)
    {
        return;
    }
    if (rx_msg->id != 0x41U)
    {
        return;
    }
    if (rx_msg->data.word[0] != 0x76543210U)
    {
        return;
    }
    g_CANFD_Test_Case_4_1_rx_received = TRUE;
}

/*******************************************************************************
 * @brief      CANFD_Test_Case_4_1
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static uint32_t CANFD_Test_Case_4_1(void)
{
    uint32_t ret;
    uint32_t msg_id;
    CANFDDriver *canfd;
    CANFDConfig config;
    CANFDTxMsg tx_msg;
    CANFDRxMsg rx_msg;

    cc_memset((uint8_t *)&config, 0, sizeof(config));
    cc_memset((uint8_t *)&tx_msg, 0, sizeof(tx_msg));
    cc_memset((uint8_t *)&rx_msg, 0, sizeof(rx_msg));

    /* STEP1 Set initialization parameters */
    config.phy_para.use_bus_clk_src = TRUE;
    config.phy_para.preamble_bit_rate = CANFD_KBPS_500;
    config.func_switch.outer_loop_back_en = TRUE;
    config.canfd_id = CANFD_MOD_ID_0;
    config.filter[0].is_valid = TRUE;


    config.filter[0].id = 0x41;
    config.filter[0].mask = 0xffffffffU;
    config.call_back.rx_received = CANFD_Test_Case_4_1_rx_received;
    /* STEP2 Initializes the CANFD module */
    ret = Canfd_LLD_Init(&canfd, &config);
    if (ret != CANFD_OK)
    {
        return ret;
    }
    /* STEP3 Send the CANFD message */
    tx_msg.data_len = 32;
    tx_msg.data.word[0] = 0x76543210;
    tx_msg.data.byte[6] = 0x55;
    tx_msg.data.byte[7] = 0x44;
    //
    tx_msg.id = 0x41;
    tx_msg.trans_buf = CANFD_TRANS_BUF_TYPE_PRIMARY;
    tx_msg.is_fd_format_flag = TRUE;
    ret = Canfd_LLD_Send_Msg(canfd, &tx_msg, &msg_id);
    if (ret != CANFD_OK)
    {
        return ret;
    }
    while (g_CANFD_Test_Case_4_1_rx_received == FALSE)
    {
        ;
    }
    return CANFD_OK;
}

/*******************************************************************************
 * @brief      CANFD_Test_Case_5_1_tx_transferred
 * @param[in]  CANFDDriver *drv, CANFDTransBufType buf_idx
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static void CANFD_Test_Case_5_1_tx_transferred(CANFDDriver *drv, CANFDTransBufType buf_idx) /* PRQA S 3673 */
{
    if (drv->id != CANFD_MOD_ID_0)
    {
        return;
    }
    if (buf_idx != CANFD_TRANS_BUF_TYPE_PRIMARY)
    {
        return;
    }
    g_CANFD_Test_Case_5_1_tx_transferred = TRUE;
}

/*******************************************************************************
 * @brief      CANFD_Test_Case_5_1
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static uint32_t CANFD_Test_Case_5_1(void)
{
    uint32_t ret;
    uint32_t msg_id;
    CANFDDriver *canfd;
    CANFDConfig config;
    CANFDTxMsg tx_msg;
    CANFDRxMsg rx_msg;

    cc_memset((uint8_t *)&config, 0, sizeof(config));
    cc_memset((uint8_t *)&tx_msg, 0, sizeof(tx_msg));
    cc_memset((uint8_t *)&rx_msg, 0, sizeof(rx_msg));

    /* STEP1 Set initialization parameters */
    config.phy_para.use_bus_clk_src = TRUE;
    config.phy_para.preamble_bit_rate = CANFD_KBPS_500;
    config.func_switch.outer_loop_back_en = TRUE;
    config.canfd_id = CANFD_MOD_ID_0;

    config.call_back.tx_transferred = CANFD_Test_Case_5_1_tx_transferred;
    /* STEP2 Initializes the CANFD module */
    ret = Canfd_LLD_Init(&canfd, &config);
    if (ret != CANFD_OK)
    {
        return ret;
    }
    /* STEP3 Send the CANFD message */
    tx_msg.data_len = 32;
    tx_msg.data.word[0] = 0x76543210;
    tx_msg.data.byte[6] = 0x55;
    tx_msg.data.byte[7] = 0x44;
    //
    tx_msg.id = 0x51;
    tx_msg.trans_buf = CANFD_TRANS_BUF_TYPE_PRIMARY;
    tx_msg.is_fd_format_flag = TRUE;
    ret = Canfd_LLD_Send_Msg(canfd, &tx_msg, &msg_id);
    if (ret != CANFD_OK)
    {
        return ret;
    }
    while (g_CANFD_Test_Case_5_1_tx_transferred == FALSE)
    {
        ;
    }
    return CANFD_OK;
}

/*******************************************************************************
 * @brief      CANFD_Test_Case_6_1
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static uint32_t CANFD_Test_Case_6_1(void)
{
    uint32_t ret;
    uint32_t msg_id;
    CANFDDriver *canfd;
    CANFDConfig config;
    CANFDTxMsg tx_msg;
    CANFDRxMsg rx_msg;

    cc_memset((uint8_t *)&config, 0, sizeof(config));
    cc_memset((uint8_t *)&tx_msg, 0, sizeof(tx_msg));
    cc_memset((uint8_t *)&rx_msg, 0, sizeof(rx_msg));

    /* STEP1 Set initialization parameters */
    config.phy_para.use_bus_clk_src = TRUE;
    config.phy_para.preamble_bit_rate = CANFD_KBPS_500;
    config.func_switch.outer_loop_back_en = TRUE;
    config.canfd_id = CANFD_MOD_ID_0;
    config.filter[0].is_valid = TRUE;


    config.filter[0].id = 0x61;
    config.filter[0].mask = 0xffffffffU;
    /* STEP2 Initializes the CANFD module */
    ret = Canfd_LLD_Init(&canfd, &config);
    if (ret != CANFD_OK)
    {
        return ret;
    }
    Canfd_LLD_Sleep(canfd);
    delayms(2000);
    Canfd_LLD_Wakeup(canfd);
    delayms(200); /* make sure CANFD recover */
    /* STEP3 Send the CANFD message */
    tx_msg.data_len = 6;
    tx_msg.data.word[0] = 0x76543210;
    tx_msg.data.byte[4] = 0x44;
    tx_msg.data.byte[5] = 0x55;
    tx_msg.data.byte[6] = 0x66;
    tx_msg.data.byte[7] = 0x70;
    //
    tx_msg.id = 0x61;
    tx_msg.trans_buf = CANFD_TRANS_BUF_TYPE_PRIMARY;
    tx_msg.is_fd_format_flag = TRUE;
    ret = Canfd_LLD_Send_Msg(canfd, &tx_msg, &msg_id);
    if (ret != CANFD_OK)
    {
        return ret;
    }
    delayms(2);
    /* STEP4 Receive the CANFD message */
    ret = Canfd_LLD_Recv_Msg(canfd, &rx_msg);
    if (ret != CANFD_OK)
    {
        return ret;
    }
    if (rx_msg.id != tx_msg.id)
    {
        return ~CANFD_OK;
    }
    return CANFD_OK;
}

/*******************************************************************************
 * @brief      CANFD_Test_Case_6_2
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
static uint32_t CANFD_Test_Case_6_2(void)
{
    uint32_t ret;
    uint32_t msg_id;
    CANFDDriver *canfd;
    CANFDConfig config;
    CANFDTxMsg tx_msg;
    CANFDRxMsg rx_msg;

    cc_memset((uint8_t *)&config, 0, sizeof(config));
    cc_memset((uint8_t *)&tx_msg, 0, sizeof(tx_msg));
    cc_memset((uint8_t *)&rx_msg, 0, sizeof(rx_msg));

    /* STEP1 Set initialization parameters */
    config.phy_para.use_bus_clk_src = TRUE;
    config.phy_para.preamble_bit_rate = CANFD_KBPS_500;
    config.func_switch.outer_loop_back_en = TRUE;
    config.canfd_id = CANFD_MOD_ID_0;
    config.filter[0].is_valid = TRUE;
    config.filter[0].id = 0x62;
    config.filter[0].mask = 0xffffffffU;
    /* STEP2 Initializes the CANFD module */
    ret = Canfd_LLD_Init(&canfd, &config);
    if (ret != CANFD_OK)
    {
        return ret;
    }
    /* STEP3 Send the CANFD message */
    tx_msg.data_len = 6;
    tx_msg.data.word[0] = 0x76543210;
    tx_msg.data.byte[4] = 0x44;
    tx_msg.data.byte[5] = 0x55;
    tx_msg.data.byte[6] = 0x66;
    tx_msg.data.byte[7] = 0x70;
    //
    tx_msg.id = 0x62;
    tx_msg.trans_buf = CANFD_TRANS_BUF_TYPE_PRIMARY;
    tx_msg.is_fd_format_flag = TRUE;
    ret = Canfd_LLD_Send_Msg(canfd, &tx_msg, &msg_id);
    if (ret != CANFD_OK)
    {
        return ret;
    }
    delayms(200); /* make sure CANFD not busy */
    Canfd_LLD_Sleep(canfd);
    delayms(2000);
    Canfd_LLD_Wakeup(canfd);
    delayms(200); /* make sure CANFD recover */
    /* STEP4 Receive the CANFD message */
    ret = Canfd_LLD_Recv_Msg(canfd, &rx_msg);
    if (ret != CANFD_OK)
    {
        return ret;
    }
    if (rx_msg.id != tx_msg.id)
    {
        return ~CANFD_OK;
    }

    return CANFD_OK;
}

/*******************************************************************************
 * @brief      CANFD_TEST_Demo
 * @param[in]  None
 * @param[out] None
 * @retval     None
 * @notapi
 *******************************************************************************/
uint32_t CANFD_TEST_Demo(void)
{
    uint32_t ret;
    uint32_t idx;
    uint32_t canfd_id;
    struct  {
        uint32_t (*func)(void);
        uint8_t auto_check;
    } const can_ut[] =
    {
        /* Function: 00 CANFD module self-loopback test */
        {CANFD_Test_Case_1_1, TRUE},
        /* Function: 01 The PC sends messages to the CANFD module */
        {CANFD_Test_Case_2_1, FALSE /* PC is required to send messages */},
        /* Function: 02 Six CANFD modules send messages to the PC */
        {CANFD_Test_Case_3_1, TRUE},
        /* Function: 03 Receive a message in an interrupt callback */
        {CANFD_Test_Case_4_1, TRUE},
        /* Function: 04 An interrupt notification was received after the message was sent asynchronously. */
        {CANFD_Test_Case_5_1, TRUE},
        /* Function: 05 Sleep and wake up after initialization */
        {CANFD_Test_Case_6_1, TRUE},
        /* Function: 06 Sleep and wake up after initialization */
        {CANFD_Test_Case_6_2, TRUE},
    };

    INTC.CPR.B.PRI = 0;

    for (idx = 0; idx < (sizeof(can_ut) / sizeof(can_ut[0])); idx++)
    {
        for (canfd_id = 0; canfd_id < (uint32_t)CANFD_MOD_BUTT; canfd_id++)
        {
            (void)Canfd_LLD_DeInit(Canfd_LLD_Get_Driver((CANFDModId)canfd_id)); /* PRQA S 4342 */
        }
        ret = (can_ut[idx].func != NULL) ? can_ut[idx].func() : CANFD_OK;
        if (ret == CANFD_OK)
        {
            continue;
        }
        else if (can_ut[idx].auto_check == FALSE)
        {
            (void)PSPRINTF("\n CCFC2011BC CAN_TEST_Demo: call %x[%x] fail, ret = 0x%x\n",
                can_ut[idx], idx, ret);
        }
        else
        {
            (void)PSPRINTF("\n CCFC2011BC CAN_TEST_Demo: FAIL\n");
            return ~CANFD_OK;
        }
    }

    (void)PSPRINTF("\n CCFC2011BC CAN_TEST_Demo: OK\n");

    return CANFD_OK;
}

